/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.admin.entity;

import vip.dexian.admin.enums.DataScopeEnum;
import vip.dexian.common.CommonAttributes;
import vip.dexian.core.base.bean.BaseEntity;
import vip.dexian.core.base.bean.UniqueOrderEntity;
import vip.dexian.core.converter.StringListConverter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Index;
import jakarta.persistence.ManyToMany;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.SuperBuilder;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.Where;
import org.hibernate.validator.constraints.Length;

import java.io.Serial;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 角色
 *
 * @author 挺好的 2023年06月01日 16:36
 */
@Entity
@Table (name = "br_admin_role",
        indexes = {@Index (name = "is_valid", columnList = "isValid"), @Index (name = "identity",
                columnList = "identity,uniqueTimestamp", unique = true)})
@DynamicUpdate
@Where (clause = BaseEntity.IS_VALID_WHERE)
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@EqualsAndHashCode (callSuper = true)
public class Role extends UniqueOrderEntity <Long> {

    @Serial
    private static final long serialVersionUID = -6020936182226853249L;

    /**
     * 角色标识
     */
    @NotEmpty (message = "角色标识不能为空")
    @Length (min = 2, max = 35, message = "角色标识长度应在2-35个字符之间")
    @Pattern (regexp = "^[0-9a-zA-Z_]+$", message = "用户名只允许数字、英文、下划线的组合")
    @Column (nullable = false, length = 35)
    @Comment ("标识")
    private String identity;

    /**
     * 角色名称
     */
    @NotEmpty (message = "角色名称不能为空")
    @Length (min = 1, max = 20, message = "角色名称的长度应在1-20个字符之间")
    @Column (nullable = false, length = 20)
    @Comment ("名称")
    private String name;

    /**
     * 角色描述信息
     */
    @Length (max = 200, message = "角色描述信息长度不可超过200个字符")
    @Column (length = 200)
    @Comment ("描述")
    private String description;

    /**
     * 是否是系统内置
     */
    @NotNull (message = "请选择是否是系统内置")
    @Column (nullable = false)
    @Comment ("系统内置。1：是，0：否")
    private Boolean isSystem;

    /**
     * 数据权限
     */
    @NotNull (message = "数据权限不能为空")
    @Column (nullable = false)
    @Comment ("数据权限，0：全部，1：本级，2：自定义")
    private DataScopeEnum dataScope;

    /**
     * 角色的权限
     */
    @NotNull (message = "权限不能为空")
    @Column (nullable = false, columnDefinition = "text")
    @Convert (converter = StringListConverter.class)
    @Comment ("权限")
    private List <String> authorities = new ArrayList <>();

    /**
     * 管理员
     */
    @ToString.Exclude
    @JsonIgnore
    @EqualsAndHashCode.Exclude
    @ManyToMany (mappedBy = "roles", fetch = FetchType.LAZY)
    private Set <Admin> admins;

    /**
     * 保存前的操作
     */
    @PrePersist
    public void prePersist () {
        if (!this.identity.startsWith(CommonAttributes.RoleSetting.ROLE_PREFIX)) {
            this.identity = CommonAttributes.RoleSetting.ROLE_PREFIX + this.identity;
        }

        this.identity = StringUtils.upperCase(this.identity);

        this.setUniqueTimestamp(CommonAttributes.UniqueKeySetting.DEFAULT_UNIQUE_TIMESTAMP);
    }

    /**
     * 更新前操作
     */
    @PreUpdate
    public void preUpdate () {
        if (!this.identity.startsWith(CommonAttributes.RoleSetting.ROLE_PREFIX)) {
            this.identity = CommonAttributes.RoleSetting.ROLE_PREFIX + this.identity;
        }
        this.identity = StringUtils.upperCase(this.identity);
    }

}
